

/**
* @file GPSTK_CC2NONCC_CPP
* Class to convert CC(cross-correlation) to NONCC(non cross-correlation).
*/

//============================================================================
//  Function:
//
//  Class to convert CC(cross-correlation) to NONCC(non cross-correlation).
//
//  Version
//
//  2016-1-26    
//  For C1/P2 receiver, the observable list maybe has P1(0),then
//  this Satelite would be filtered, this result is unreasonable,
//  so we delete the P1 filter.(Q.Liu)
//
//  2016-4-18    
//  Add the exception when DCB file is not provided, and we will
//  not do the DCB correction and will output the error message,
//  but not stop the data processing work.(Q.Liu)
//
//  2019. s.j.zhang, modify 
//============================================================================

#include "CC2NONCC.hpp"


using namespace std;

namespace gpstk
{

      // Return a string identifying this object.
    string CC2NONCC::getClassName() const
    { return "CC2NONCC"; }


      /* Return a satTypeValueMap object, adding the new data generated
       *  when calling this object.
       *
       * @param time      Epoch corresponding to the data.
       * @param gData     Data object holding the data.
       */
    satTypeValueMap& CC2NONCC::Process( const CommonTime& time,
                                        satTypeValueMap& gData ) 
       noexcept(false)
    {
        try
        {
            SatIDSet satRejectedSet;

	        bool nonccType(false);

	        // The receiver type can be judge by the first satellite obs.
            for(satTypeValueMap::iterator it = gData.begin();
                it != gData.end();
                ++it)
            {
                SatID sat( it->first );
                if(sat.system == SatelliteSystem::GPS)
                {
                    typeValueMap::iterator itC1W( it->second.find(TypeID::C1W) );

		            // which type?
		            nonccType = (itC1W != it->second.end()) && ( (*itC1W).second !=0.0);
		            if(nonccType)
		            {
		              continue;
		            }
		            else
		            {
	 	               if(usingCCData)
		               {
                          if(dcbP1C1 != NULL)
                          {
                             // Get the Sat's DCB value, unit:ns
                             double Bp1c1(0.0);     
                             Bp1c1 = (*dcbP1C1).getDCB(sat);

                             typeValueMap::iterator itC1C = it->second.find(TypeID::C1C);
                             // For receiver noncc (C1,P2)
                             // For the noncc: only C1 should be corrected
                             // C1 -> C1 + (P1-C1)
                             if(itC1C != it->second.end())
                             {
                                 // Correct
                                 it->second[TypeID::C1W] = it->second[TypeID::C1C] +
                                                           C_MPS* Bp1c1 * 1.0e-9;
                             }
		                     else
		                     {
                                 satRejectedSet.insert( sat );
		                     }

                          } // End of 'if(dcbP1C1 != NULL)'
		                  else
		                  {
		                     cerr << "NO DCB file exist!" << endl;
		                     exit(-1);
		                  }
		               }
		               else
		               {
                          satRejectedSet.insert( sat );
		               }
		            }
                }
            }  // End of 'for (it = gData.begin(); it != gData.end(); ++it)'

            gData.removeSatID(satRejectedSet);

	        // now, let's print the corrected values
            return gData;
        }
        catch(Exception& u)
        {
            // Throw an exception if something unexpected happens
            ProcessingException e( getClassName() + ":" + u.what() );
            GPSTK_THROW(e);
        }

    }  // End of method 'CC2NONCC::Process()'


    /** Return a sourceRinex object, adding the new data generated
     *  when calling this object.
     *
     * @param gData     Data object holding the data.
     */
    void CC2NONCC::Process(commonHeader& comHeader, sourceRinex& gData) 
    {
           // set dcb file pointer from ggd;
        dcbP1C1 = comHeader.pDCBStore;

        CommonTime epoch(gData.header.epoch);

        for( sourceDataMap::iterator sdmIt = gData.body.begin();
             sdmIt != gData.body.end();
             ++sdmIt )
        {
            Process( epoch, sdmIt->second );
        }

    }  // End of method 'CC2NONCC::Process()'

}  // End of namespace gpstk
